//
//  Character.m
//
//  Created by Scott Guyer on 3/21/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "Character.h"
#import "Skill.h"
#import "defs.h"


@implementation Character

static NSArray* attributeNames = nil;

@synthesize userID;
@synthesize apiKey;
@synthesize charID;

@synthesize       name;
@synthesize       corporationName;
@synthesize       iskies;
@synthesize       race;
@synthesize       bloodline;
@synthesize       gender;
@synthesize       skillPoints = _skillPoints;
@synthesize       skills      = _skillsDict;
@synthesize       needsReload = _needsReload;
@synthesize       skillTrainingDict;

@synthesize       characterDataLastLoad;
@synthesize       characterDataCachedUntil;
@synthesize       trainingDataLastLoad;
@synthesize       trainingDataCachedUntil;


+ (void) initialize
{
	// NOTE: this has to match the PilotAttrType enum 	
	attributeNames = [[NSArray alloc] initWithObjects:@"Intelligence", @"Memory", @"Charisma", @"Perception", @"Willpower", nil];
}

+ (NSString*) nameForAttribute:(PilotAttrType)att 
{
	if ( (att >= kPilotAttrTypeIntel) && (att < kPilotAttrTypeCount) )
		return (NSString*) [attributeNames objectAtIndex:att];
	else
		return @"";
}

- (id) init
{
	if ( (self = [super init]) != nil )
	{
		_skillsDict = [[NSMutableDictionary alloc] init];
		_learningSkill = 0;
		_recalcEffectiveAttributes = YES;
		_needsReload = YES;
		
		characterDataLastLoad = nil;
		characterDataCachedUntil = nil;
		trainingDataLastLoad = nil;
		trainingDataCachedUntil = nil;
	}
	
	return self;
}



- (NSString*) getDescription
{
	return [NSString stringWithFormat:@"%@ %@ %@", 
			(gender == nil) ? [NSString string] : gender, 
			(nil == race) ? [NSString string] : race, 
			(nil == bloodline) ? [NSString string] : bloodline];
}


- (NSInteger) getAttribute:(PilotAttrType)attType
{
	if ( (attType >= kPilotAttrTypeIntel) && (attType < kPilotAttrTypeCount) )
		return _attributes[attType];
	else
		return 0;
}

- (void) setAttribute:(PilotAttrType)attType withValue:(NSInteger)value
{
	if ( (attType >= kPilotAttrTypeIntel) && (attType < kPilotAttrTypeCount) )
		_attributes[attType] = value;
	_recalcEffectiveAttributes = YES;
}

- (NSInteger) getImplantBonus:(PilotAttrType)attType
{
	if ( (attType >= kPilotAttrTypeIntel) && (attType < kPilotAttrTypeCount) )
		return _implants[attType];
	else
		return 0;	
}

- (void) setImplantBonus:(PilotAttrType)attType withValue:(NSInteger)value
{
	if ( (attType >= kPilotAttrTypeIntel) && (attType < kPilotAttrTypeCount) )
		_implants[attType] = value;
	_recalcEffectiveAttributes = YES;
}


- (void) recalcEffAtts
{
	Skill* sp = (Skill*)[_skillsDict valueForKey:@kSkillTypeID_Learning];
	if ( sp != nil )
	{
		_learningSkill = sp.level;
	}
	
	
	// Intel
	sp = (Skill*)[_skillsDict valueForKey:@kSkillTypeID_AnalyticalMind];
	if ( sp != nil )
	{
		_basicSkillLevel[kPilotAttrTypeIntel] = sp.level;
	}
	
	sp = (Skill*)[_skillsDict valueForKey:@kSkillTypeID_Logic];						  
	if ( sp != nil )
	{
		_advSkillLevel[kPilotAttrTypeIntel] = sp.level;
	}			
	
	_effectiveAttributes[kPilotAttrTypeIntel] = 
			(_attributes[kPilotAttrTypeIntel] + _implants[kPilotAttrTypeIntel] + _basicSkillLevel[kPilotAttrTypeIntel] + _advSkillLevel[kPilotAttrTypeIntel])
			* (1 + (0.02 * _learningSkill)) ;	

	// Memory
	sp = (Skill*)[_skillsDict valueForKey:@kSkillTypeID_InstantRecall];
	if ( sp != nil )
	{
		_basicSkillLevel[kPilotAttrTypeMemory] = sp.level;
	}
	
	sp = (Skill*)[_skillsDict valueForKey:@kSkillTypeID_EideticMemory];						  
	if ( sp != nil )
	{
		_advSkillLevel[kPilotAttrTypeMemory] = sp.level;
	}			
	
	_effectiveAttributes[kPilotAttrTypeMemory] = 
		  (_attributes[kPilotAttrTypeMemory] + _implants[kPilotAttrTypeMemory] + _basicSkillLevel[kPilotAttrTypeMemory] + _advSkillLevel[kPilotAttrTypeMemory])
		  * (1 + (0.02 * _learningSkill))  ; 

	
	// Charisma
	sp = (Skill*)[_skillsDict valueForKey:@kSkillTypeID_Empathy];
	if ( sp != nil )
	{
		_basicSkillLevel[kPilotAttrTypeCharisma] = sp.level;
	}
	
	sp = (Skill*)[_skillsDict valueForKey:@kSkillTypeID_Presence];						  
	if ( sp != nil )
	{
		_advSkillLevel[kPilotAttrTypeCharisma] = sp.level;
	}			
	
	_effectiveAttributes[kPilotAttrTypeCharisma] = 
		  (_attributes[kPilotAttrTypeCharisma] + _implants[kPilotAttrTypeCharisma] + _basicSkillLevel[kPilotAttrTypeCharisma] + _advSkillLevel[kPilotAttrTypeCharisma])
	* (1 + (0.02 * _learningSkill)) ;
	

	// Perception
	sp = (Skill*)[_skillsDict valueForKey:@kSkillTypeID_SpatialAwareness];
	if ( sp != nil )
	{
		_basicSkillLevel[kPilotAttrTypePerception] = sp.level;
	}
	
	sp = (Skill*)[_skillsDict valueForKey:@kSkillTypeID_Clarity];						  
	if ( sp != nil )
	{
		_advSkillLevel[kPilotAttrTypePerception] = sp.level;
	}			
	
	_effectiveAttributes[kPilotAttrTypePerception] = 
		  (_attributes[kPilotAttrTypePerception] + _implants[kPilotAttrTypePerception] + _basicSkillLevel[kPilotAttrTypePerception] + _advSkillLevel[kPilotAttrTypePerception])
		* (1 + (0.02 * _learningSkill)) ;

	
	// Willpower
	sp = (Skill*)[_skillsDict valueForKey:@kSkillTypeID_IronWill];
	if ( sp != nil )
	{
		_basicSkillLevel[kPilotAttrTypeWillpower] = sp.level;
	}
	
	sp = (Skill*)[_skillsDict valueForKey:@kSkillTypeID_Focus];						  
	if ( sp != nil )
	{
		_advSkillLevel[kPilotAttrTypeWillpower] = sp.level;
	}			
	
	_effectiveAttributes[kPilotAttrTypeWillpower] = 
		  (_attributes[kPilotAttrTypeWillpower] + _implants[kPilotAttrTypeWillpower] + _basicSkillLevel[kPilotAttrTypeWillpower] + _advSkillLevel[kPilotAttrTypeWillpower])
		* (1 + (0.02 * _learningSkill)) ;  
	
}

- (float) getEffectiveAttribute:(PilotAttrType)attType
{
	if ( (attType < kPilotAttrTypeIntel) || (attType >= kPilotAttrTypeCount) )
		return 0;
	
	if ( _recalcEffectiveAttributes )
	{		
		[self recalcEffAtts];
		_recalcEffectiveAttributes = NO;
	}
	
	return _effectiveAttributes[attType];
}


+ (BOOL)writeApplicationData:(NSData *)data toFile:(NSString *)fileName { 
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
														 NSUserDomainMask, YES); 
	NSString *documentsDirectory = [paths objectAtIndex:0]; 
	if (!documentsDirectory) { 
		NSLog(@"Documents directory not found!"); 
		return NO; 
	} 
	NSString *appFile = [documentsDirectory 
						 stringByAppendingPathComponent:fileName]; 
	return ([data writeToFile:appFile atomically:YES]); 
}

+ (NSData *)applicationDataFromFile:(NSString *)fileName { 
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
														 NSUserDomainMask, YES); 
	NSString *documentsDirectory = [paths objectAtIndex:0]; 
	NSString *appFile = [documentsDirectory 
						 stringByAppendingPathComponent:fileName]; 
	NSData *myData = [[[NSData alloc] initWithContentsOfFile:appFile] 
					  autorelease]; 
	return myData; 
} 

+ (NSMutableArray*) loadPilots
{
	
//	NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
//	NSString* pilotsFile = [bundlePath stringByAppendingPathComponent:@"pilots.plist"];
	NSMutableArray* pilots = [[NSMutableArray alloc] init];

//	NSFileManager *fileMan = [NSFileManager defaultManager];
//	if ( ! [fileMan fileExistsAtPath:pilotsFile] )
//		return nil;
	
//	NSData* xmlData = [NSData dataWithContentsOfFile:pilotsFile];
	NSData* xmlData = [Character applicationDataFromFile:@"pilots.plist"];
	if ( xmlData == nil )
	{
		NSLog(@"unable to read pilots file");
		[pilots release];
		return nil;
	}
	
	
	NSString* error;
	NSPropertyListFormat fmt = NSPropertyListXMLFormat_v1_0;
	NSArray* plist = [NSPropertyListSerialization propertyListFromData:xmlData	
													  mutabilityOption:NSPropertyListImmutable 
																format:&fmt 
													  errorDescription:&error];
	if( plist == nil )
	{
		NSLog(error);
		[pilots release];
		return nil;
	}
		
	Character* c;
	for ( NSDictionary* charDict in plist )
	{
		c = [[Character alloc] init];
		
		c.userID = (NSString*)[charDict objectForKey:@"userID"];
		c.apiKey = (NSString*)[charDict objectForKey:@"apiKey"];
		c.charID = (NSString*)[charDict objectForKey:@"charID"];
		c.name = (NSString*)[charDict objectForKey:@"name"];
//		c.corporationName = (NSString*)[charDict objectForKey:@"corpName"];
//		c.gender = (NSString*)[charDict objectForKey:@"gender"];
//		c.race = (NSString*)[charDict objectForKey:@"race"];
//		c.bloodline = (NSString*)[charDict objectForKey:@"bloodline"];
//		c.iskies = (NSString*)[charDict objectForKey:@"isk"];
//		c.skillPoints = [(NSString*)[charDict objectForKey:@"skillpoints"] integerValue];
		
		[pilots addObject:c];
		[c release];
	}
	
	return pilots;
}


- (Character*) updateCharacterDataFrom:(Character*)newC 
{
	if ( newC == nil )
		return self;
	
	_needsReload = NO;

/*	
	self.name = [newC.name;
	self.corporationName = [newC.corporationName;
	self.race = [newC.race;
	self.bloodline = [newC.bloodline;
	self.gender = [newC.gender;
	self.iskies = [newC.iskies;
	self.characterDataLastLoad = [newC.characterDataLastLoad;
	self.characterDataCachedUntil = [newC.characterDataCachedUntil;
*/

	self.name = newC.name;
	self.corporationName = newC.corporationName;
	self.race = newC.race;
	self.bloodline = newC.bloodline;
	self.gender = newC.gender;
	self.iskies = newC.iskies;
	self.characterDataLastLoad = newC.characterDataLastLoad;
	self.characterDataCachedUntil = newC.characterDataCachedUntil;
	
	
	for ( int i=0; i<kPilotAttrTypeCount; i++ )
	{
		_attributes[i] = [newC getAttribute:i];
		_implants[i]   = [newC getImplantBonus:i];
	}	
	_recalcEffectiveAttributes = YES;
	
	self.skillPoints = newC.skillPoints;
	
	if ( _skillsDict != nil )
		[_skillsDict release];
	_skillsDict = newC.skills;
	[_skillsDict retain];
	
	return self;
}


 

+ (Boolean) savePilots:(NSArray*)pilots
{
	if ( pilots == nil )
		return NO;

	// TODO: if [pilots count] == 0, I could just nuke the file and skip all
	// the code below.
	
	// Build Property List
	
	NSMutableArray* plist = [[NSMutableArray alloc] init];
//	NSString* tmpStr;
	NSMutableDictionary* charDict;
	for ( Character* c in pilots )
	{
		charDict = [[NSMutableDictionary alloc] init];
		[charDict setObject:c.userID forKey:@"userID"];
		[charDict setObject:c.apiKey forKey:@"apiKey"];
		[charDict setObject:c.charID forKey:@"charID"];
		[charDict setObject:c.name forKey:@"name"];
//		[charDict setObject:c.corporationName forKey:@"corpName"];
//		[charDict setObject:c.gender forKey:@"gender"];
//		[charDict setObject:c.race forKey:@"race"];
//		[charDict setObject:c.bloodline forKey:@"bloodline"];
//		[charDict setObject:c.iskies forKey:@"isk"];
//		tmpStr = [NSString stringWithFormat:@"%d", c.skillPoints];
//		[charDict setObject:tmpStr forKey:@"skillpoints"];
		[plist addObject:charDict];
		[charDict release];
	}
	
	
	// Now write it out
	
	NSData *xmlData;
	NSString *error;
	xmlData = [NSPropertyListSerialization dataFromPropertyList:plist
														 format:NSPropertyListXMLFormat_v1_0
											   errorDescription:&error];
	
	[plist release];
	
	if(xmlData)
	{
		[Character writeApplicationData:xmlData toFile:@"pilots.plist"];
//		NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
//		NSString* filePath = [bundlePath stringByAppendingPathComponent:@"pilots.plist"];		
//		[xmlData writeToFile:filePath atomically:YES];
	}
	else
	{
		NSLog(error);
		[error release];
	}
	
	return YES;
}


- (int) skillPointsPerHourWithPrimary:(PilotAttrType)pri andSecondary:(PilotAttrType)sec 
{

	if ( (pri < 0) || (pri >= kPilotAttrTypeCount) )
		return 0;

	if ( (sec < 0) || (sec >= kPilotAttrTypeCount) )
		return 0;

	float priEffAtt = [self getEffectiveAttribute:pri];
	float secEffAtt = [self getEffectiveAttribute:sec];
	
	int result = ( priEffAtt + (secEffAtt / 2.0) ) * 60 ;
	
	return result;
}



- (void) dealloc
{
	NSLog(@"%s 0x%x", __FUNCTION__, self);

	
	WIPE( skillTrainingDict)
	WIPE( _skillsDict)	 	
	WIPE( userID)
	WIPE( apiKey)
	WIPE( charID)
	WIPE( name)
	WIPE( corporationName)
	WIPE( iskies)
	WIPE( race)
	WIPE( bloodline)
	WIPE( gender)	
	
	WIPE( characterDataLastLoad)
	WIPE( characterDataCachedUntil)
	WIPE( trainingDataLastLoad)
	WIPE( trainingDataCachedUntil)
	
	
	[super dealloc];
}

@end
